#include"head.h"
#include"funcs.h"
#include"nodes.h"

extern unordered_map<char,node*> buf;
extern vector<string> Rules;
extern std::unordered_map<char, int> dic;

node::node(string& rule) {
	vector<string> temp = split(rule, '@');

	rule = temp[0] + temp[1] + string("#");//prepare for the find_follow process 

	this->nonTerminal = temp[0][0];
	this->prods = temp[1];

	this->firstSets;
	this->followSets;

}

unordered_set<int>& node::findFirst() {
	if (!this->firstSets.empty()) {
		return this->firstSets;
	}

	vector<string> prod = split(this->prods, '|');
	for (string& line : prod) {
		if (line[0] == Epi) {
			this->firstSets.insert(Epi);
		}
		else if (isEnding(line[0])) {
			this->firstSets.insert(dic[line[0]]);
		}
		else {
			setUnion(this->firstSets, buf[line[0]]->findFirst());
		}
	}

	return this->firstSets;
}


unordered_set<int>& node::findFollow() {
	if (!this->followSets.empty()) {
		return this->followSets;
	}

	for (string& prode : Rules) {
		vector<string> prod = split(prode, '|');

		for (auto &line : prod) {
			int point = inString(line, this->nonTerminal, 1);
			if (point + 1) {
				point++;
				if (isEnding(line[point])) {
					this->followSets.insert(dic[line[point]]);
				}
				else if (line[point] == '#') {
					this->followSets.insert('#');
				}
				else {
					auto flag = buf[line[point]]->firstSets.find(Epi);

					setUnion(this->followSets, buf[line[point]]->findFirst(), 1);

					if (flag == buf[line[point]]->firstSets.end()) {
						setUnion(this->followSets, buf[line[0]]->findFollow());
					}

				}
			}
		}
	}

	return this->followSets;
}
